#! /usr/bin/env python

import getpass
import os
import urllib
import urllib2
from xml.dom import minidom
import string
import datetime
import sys
import md5
from optparse import OptionParser
from time import strftime

version = 0.7

def showVersion(verbose):
	if verbose:
		print "Current version of gdd.py:", version
	try:
		vreq = urllib2.Request("http://www.1st-soft.net/gdd/version2.txt")
		vresponse = urllib2.urlopen(vreq).read()
		if verbose:
			print "Most recent version is " + vresponse.strip()
		if float(vresponse) > version:
			print "Your version of gdd.py is out of date!"
			print "Visit http://www.1st-soft.net/gdd for an updated version."
		else:
			if verbose:
				print "gdd.py is currently up to date."
	except urllib2.HTTPError:
		if verbose:
			print "Could not contact 1st-soft.net for most recent version."
	


feed = "https://docs.google.com/feeds/documents/private/full"
dlall = True
recordtolog = True
datetag = None

formats = {'mso':("doc","4","ppt"),'csv':("txt","5&gid=0","txt"),'oo':("odt","13","ppt"),'pdf':("pdf","12","pdf"),'txt':("rtf","23&gid=0","txt"),}
format = "mso"
docfmt = formats[format][0]
spdfmt = formats[format][1]
prsfmt = formats[format][2]

filesdownloaded = []

cmdemail = ""
cmdpass = ""
path = ""
use_unicode = False
datetag = ""





for arg in sys.argv:
	if arg.find("--feed=")==0:
		val = arg.partition("=")[2]
		feed = val
		print feed
	if arg == "--modified-only" or arg == "-m":
		dlall = False
	if arg == "--version" or arg == "-v":
		print "Current version of gdd.py:", version
		try:
			vreq = urllib2.Request("http://www.1st-soft.net/gdd/version2.txt")
			vresponse = urllib2.urlopen(vreq).read()
			print "Most recent version is " + vresponse.strip()
			if float(vresponse) > version:
				print "Your version of gdd.py is out of date!"
				print "Visit http://www.1st-soft.net/gdd for an updated version."
			else:
				print "gdd.py is currently up to date."
		except urllib2.HTTPError:
			print "Could not contact 1st-soft.net for most recent version."
		sys.exit(0)
	if arg == "--help" or arg == "-h":
		print "Please see readme.txt"
		sys.exit(0)
	if arg.find("--format=")==0:
		format = arg.partition("=")[2]
		if format in formats:
			docfmt = formats[format][0]
			spdfmt = formats[format][1]
			prsfmt = formats[format][2]
	if arg.find("--document-format=")==0:
		val = arg.partition("=")[2]
		if val in formats:
			docfmt = formats[val][2]
		else:
			docfmt = val
	if arg.find("--spreadsheet-format=")==0:
		val = arg.partition("=")[2]
		if val in formats:
			spdfmt = formats[val][2]
		else:
			spdfmt = val
	if arg.find("--presentation-format=")==0:
		val = arg.partition("=")[2]
		if val in formats:
			prsfmt = formats[val][2]
		else:
			prsfmt = val
	if arg.find("--email=")==0:
		val = arg.partition("=")[2]
		cmdemail = val
	if arg.find("--password=")==0:
		val = arg.partition("=")[2]
		cmdpass = val
	if arg.find("--path=")==0:
		val = arg.partition("=")[2]
		if os.path.exists(val):
			path = val + "/"
			path = string.replace(path,"//","/")
	if arg.find("--unicode")==0 or arg.find("-u")==0:
		use_unicode == True
	if arg.find("--datetag")==0 or arg.find("-d")==0:
		datetag = strftime("%Y-%m-%d_%H:%M:%S")







def login():
	global path
	global datetag
	
	
	if cmdemail == "":
		email = raw_input("Email: ")
	else:
		email = cmdemail
	if cmdpass == "":
		password = getpass.getpass()
	else:
		password = cmdpass
	
	"""
	print email
	print password
	"""
	
	email = email
	password = password
	
	url = 'https://www.google.com/accounts/ClientLogin'
	user_agent = 'GDD Python ' + str(version)
	values = {'Email' : email, 'Passwd' : password, 'accountType' : 'HOSTED_OR_GOOGLE', 'service' : 'writely', 'source' : user_agent, 'GData-Version': '2.0' }
	values2 = {'Email' : email, 'Passwd' : password, 'accountType' : 'HOSTED_OR_GOOGLE', 'service' : 'wise', 'source' : user_agent, 'GData-Version': '2.0' }
	headers = { 'User-Agent' : user_agent }

	try:
		data = urllib.urlencode(values)
		data2 = urllib.urlencode(values2)
		req = urllib2.Request(url, data, headers)
		req2 = urllib2.Request(url, data2, headers)
		response = urllib2.urlopen(req)
		response2 = urllib2.urlopen(req2)
		docauth = response.read()
		docauth = docauth.splitlines()[2].split("=")[1]
		spreadauth = response2.read()
		spreadauth = spreadauth.splitlines()[2].split("=")[1]
	
		if(os.path.exists(path+email) == False):
			os.mkdir(path+email)
		
		
		return (email,docauth,spreadauth)
	
	except urllib2.HTTPError, e:
		print "Authentication failed"
		print e
		sys.exit(0)
		return ("","","")
	except urllib2.URLError, e:
		print "Authentication failed"
		print e.reason
		sys.exit(0)
		return ("","","")


def getFeed(auth,feed,lastdate):
	try:
		url = feed
		if not dlall and lastdate != None and url.find("?")==-1:
			url = url + "?" + "updated-min=" + lastdate
		elif not dlall and lastdate != None and url.find("?")!=-1:
			url = url + "&" + "updated-min=" + lastdate
		"""
		if url.find("?")==-1 and options.folders:
			url = url + "?" + "showfolders=true"
		elif url.find("?")!=-1 and options.folders:
			url = url + "&" + "showfolders=true"
		"""
		user_agent = 'GDD Python 0.01'
		req = urllib2.Request(url)
		req.add_header('Authorization','GoogleLogin auth='+auth[1])
		response = urllib2.urlopen(req)
		feedxml = response.read()
		return feedxml
	except:
		print "Feed request failed"
		sys.exit(0)
		return ""


def parseFeed(xml):
	dom = minidom.parseString(xml)
	docs = []
	urls = []
	folders = []
	for node in dom.getElementsByTagName('entry'):
		updated = ''
		parent = ''
		title = ''
		doc = ''
		id = ''
		for i in node.childNodes:
			if i.nodeName == 'gd:resourceId':
				doc = i.childNodes[0].nodeValue
			if i.nodeName == 'updated':
				updated = i.childNodes[0].nodeValue
			if i.nodeName == 'title':
				title = i.childNodes[0].nodeValue
			if i.nodeName == 'id':
				id = i.childNodes[0].nodeValue
			if i.nodeName == 'link' and i.attributes.keys().count('rel') > 0:
				if i.attributes['rel'].value.find("#parent") != -1 and i.attributes.keys().count('href') > 0:
					parent = i.attributes['href'].value
		docs.append({'doc':doc,'title':title,'parent':parent,'id':id})
	for x in docs:
		z = string.split(x['doc'],":")
		type = z[0]
		id = z[1]
		title = x['title']
		if type == "document":
			urls.append({'parent':x['parent'],'id':x['id'],'type':type,'title':title,'url':"https://docs.google.com/feeds/download/documents/Export?docID="+id+"&exportFormat="+docfmt})
		elif type == "spreadsheet":
			urls.append({'parent':x['parent'],'id':x['id'],'type':type,'title':title,'url':"https://spreadsheets.google.com/feeds/download/spreadsheets/Export?key="+id+"&fmcmd="+spdfmt})
		elif type == "pdf":
			urls.append({'parent':x['parent'],'id':x['id'],'type':type,'title':title,'url':"https://docs.google.com/gb?export=download&id=F."+id})
		elif type == "presentation":
			urls.append({'parent':x['parent'],'id':x['id'],'type':type,'title':title,'url':"https://docs.google.com/feeds/download/presentations/Export?docID="+id+"&exportFormat="+prsfmt})
		elif type == "folder":
			folders.append({'parent':x['parent'],'id':x['id'],'title':title,'children':[]})
	return {'urls':urls,'folders':folders}


def getFile(doc,headers,dname):
	global options
	global filesdownloaded
	if dname != "" and dname[-1] != "/":
		dname = dname+"/"
	req = urllib2.Request(doc['url'])
	for k, v in headers.iteritems():
		req.add_header(k, v)
	try:
		f = urllib2.urlopen(req)
		
		
		cderror = False
		fname = "Document"
		if(f.info().getheader('Content-Disposition') != None and f.info().getheader('Content-Disposition') != ""):
			fname = f.info().getheader('Content-Disposition').partition("=")
			
			if fname[1] != "":
				fname = fname[2]
			else:
				fname = fname[0]
				cderror = True
			fname = urllib2.unquote(fname)
			fname = string.replace(fname,"\"","")
			fname = string.replace(fname,"/","_")
			fname = string.replace(fname,"\\","_")
			
			# testing new file naming method
			if cderror == False:
				ext = "."+fname.split(".").pop()
			else:
				ext = ""
			nfname = doc['title']
			nfname = string.replace(nfname," ","_")
			nfname = string.replace(nfname,"\"","")
			nfname = string.replace(nfname,"/","_")
			nfname = string.replace(nfname,"\\","_")
			nfname = nfname+ext
			if use_unicode or cderror:
				fname = nfname
		else:
			cderror = True
		
		ofname = fname.split(".") # original file name
		if len(ofname) > 1:
			ofnameext = "."+ofname.pop()
		else:
			ofnameext = ""
		ofname = string.join(ofname,".")
		dupcount = 1
		while os.path.exists(dname+fname) and filesdownloaded.count(fname) > 0:
			fname = ofname+"_"+str(dupcount)+ofnameext
			dupcount+=1
		
		
		
		print "Downloading " + fname.encode("utf-8") + "...",
		sys.stdout.flush()
		
		
		local = open(dname+fname, "wb")
		
		filesdownloaded.append(fname)
		
		chunkSize = 10240
		while 1:
			dbuffer = f.read(chunkSize)
			if dbuffer:
				local.write(dbuffer)
			else:
				break
		
			
		local.close()
		print " done"
		return {'success':True,'file':fname}
	except urllib2.HTTPError, e:
		print "There was an error downloading " + doc['url']
		print e
		return {'success':False,'file':''}
	except urllib2.URLError, e:
		print "There was an error downloading " + doc['url']
		print e.reason
		return {'success':False,'file':''}


def download(auth,urls):
	docs = urls
	global datetag
	global path
	noerror = True
	files = []
	if datetag != None:
		dtpath = "/"+datetag
	else:
		dtpath = ""
	for i in docs:
		if i['type'] != "spreadsheet":
			result = getFile(i,{'Authorization':'GoogleLogin auth=' + auth[1], 'GData-Version': '2.0'}, path+auth[0]+dtpath)
			noerror = result['success'] and noerror
			files.append(result['file'])
		else:
			result = getFile(i,{'Authorization':'GoogleLogin auth=' + auth[2], 'GData-Version': '2.0'}, path+auth[0]+dtpath)
			noerror = result['success'] and noerror
			files.append(result['file'])
	return {'success':noerror,'files':files}


def getInfo(data,keys,type):
	rdata = []# return data
	if data[0].keys().count(type) > 0:
		for x in keys:
			for y in data:
				if x == y['id']:
					rdata.append(y[type])
		return rdata
	else:
		return []


def listDir(data,lv=0,dir=['']):
	# path/auth[0]/datetag/dir
	print string.join(getInfo(data['folders'],dir,'title'),"/")
	current = dir[-1]
	for x in data['folders']:
		if x['parent'] == current:
			print (lv*'\t') + x['title']
			temp = dir
			temp.extend([x['id']])
			listDir(data,lv+1,temp)
	for x in data['urls']:
		if x['parent'] == current:
			print (lv*'\t') + x['title']





if path != "" and path[-1] != "/":
	path = path+"/"

print "Welcome to Google Docs: Download for Python"
print "Authenticating..."
auth = login()
print "Authentication Successful!"

if not os.path.exists("log.txt"):
	z = open("log.txt","w")
	z.close()

f = open("log.txt","r")
while 1:
	d = f.readline()
	if d and d.strip() != "":
		d = d.split(" :: ")
		if d[0].strip() == auth[0] and d[2].strip() == feed:
			lastdate = d[1].strip()
			break
	else:
		lastdate = None
		break
f.close()

print "Retrieving list of documents..."
feedxml = ""
if auth[0] != "" and auth[1] != "":
	feedxml = getFeed(auth,feed,lastdate)
if feedxml != "":
	print "Document list retrieved."
	docfeed = parseFeed(feedxml)
	
	urls = docfeed['urls']
	print "Downloading your documents..."
	if datetag != None and os.path.exists(path+auth[0]+"/"+datetag) == False:
		os.mkdir(path+auth[0]+"/"+datetag)
	
	result = download(auth,urls)
	recordtolog = result['success'] and recordtolog
	
	print "files downloaded"


if auth[0] != "" and auth[1] != "":
	dom = minidom.parseString(feedxml)
	thedate = dom.getElementsByTagName('updated')[0].childNodes[0].nodeValue
	
	if(os.path.exists("data") == False):
		os.mkdir("data")
	m = md5.new()
	m.update(auth[0]+" :: "+feed)
	f = open("data/"+m.hexdigest()+".xml", "w")
	f.write(feedxml)
	f.close()
	
	if recordtolog:
		print "Writing session information to log.txt..."
		os.rename("log.txt","log.txt.old")
		z = open("log.txt.old","r")
		f = open("log.txt", "w")
		f.write(auth[0]+" :: "+thedate+" :: "+feed+"\n")
		while 1:
			d = z.readline()
			if d:
				f.write(d)
			else:
				break
		f.close()
		z.close()
		os.remove("log.txt.old")
	else:
		print "There were some errors while downloading your files.  Session will not be recorded to log.txt."
	
	
	print "All done!"
	print "\n"
	showVersion(False)


# This software is licensed under the CC-GNU GPL.
# http://creativecommons.org/licenses/GPL/2.0/
# Google Docs: Download for Python was written by Peter Shafer, in June 2009.

